/*
	klib_proc_threads.c

	contains the threading functionality accessible from drivers and usermode

	ALL FUNCTIONS ARE INTENDED TO BE CALLED WITH INTERRUPTS ENABLED

	Author: Aidan Goddard 18/8/13
*/

#include"headers/ktypes.h"
#include"headers/klib_proc_threads.h"
#include"../kernel/headers/scheduler_functions.h"
#include"../kernel/headers/process_control.h"

// function to spawn a new thread
// param0 = thread entry point
// param1 = pointer to optional data structure which is passed to the thread at start
// param2 = stack pointer
// returns TID of new thread
uint64_t	__KLIB__SpawnNewThread(uint64_t(*start_address)(void*), void *data, void *stack_ptr)
{
	// disable interrupts
	__asm__ __volatile__("":::"memory");
	__asm__ __volatile__("cli");
	__asm__ __volatile__("":::"memory");

	// call the system function
	uint64_t to_return = SpawnSlaveThread(start_address, data, stack_ptr);

	// reenable interrupts
	__asm__ __volatile__("":::"memory");
	__asm__ __volatile__("sti");
	__asm__ __volatile__("":::"memory");

	// finished, return
	return to_return;
}

// function to terminate the calling thread
// param0 = thread's return value
void		__KLIB__KillThisThread(uint64_t return_value)
{
	// call the system function
	KillThisThread(return_value);
	return;
}

// function to make the current thread wait indefinitely
// no params
// returns the message passed to it when it was woken
uint64_t	__KLIB__WaitThisThread(void)
{
	// call the system function
	uint64_t to_return = WaitMe();
	return to_return;
}

// function to put the current thread to sleep for a given amount of time in us (micro seconds)
// param0 = time to sleep in micro seconds
// returns the message passed to it if it was woken by something else
uint64_t	__KLIB__SleepThisThread(uint32_t sleep_time)
{
	// call the system function
	uint64_t to_return = SleepMe(sleep_time);
	return to_return;
}

// function to wake the given thread
// param 0 = TID to wake
// param 1 = message to send to the woken thread
uint32_t	__KLIB__WakeThread(uint64_t TID, uint64_t message)
{
	// first check if the thread is in the same process
	// disable interrupts
	__asm__ __volatile__("":::"memory");
	__asm__ __volatile__("cli");
	__asm__ __volatile__("":::"memory");

	// get the current TID
	uint64_t current_TID = GetCurrentTID();

	// check if the PID matches
	// mask the bottom byte
	uint64_t test_TID = TID & 0xffffffffffffff00;
	current_TID = current_TID & 0xffffffffffffff00;

	uint32_t to_return = WAKE_THREAD_NOT_IN_PROC;

	if(test_TID == current_TID)
	{
		to_return = WakeThread(TID, message);
	}

	// reenable interrupts
	__asm__ __volatile__("":::"memory");
	__asm__ __volatile__("sti");
	__asm__ __volatile__("":::"memory");

	// finished, return
	return to_return;
}

// function to wake an external thread
uint32_t	__KLIB__WakeThreadEx(uint64_t TID)
{
	// disable interrupts
	__asm__ __volatile__("":::"memory");
	__asm__ __volatile__("cli");
	__asm__ __volatile__("":::"memory");

	uint32_t to_return = WakeThreadEx(TID);

	// reenable interrupts
	__asm__ __volatile__("":::"memory");
	__asm__ __volatile__("sti");
	__asm__ __volatile__("":::"memory");

	// finished, return
	return to_return;
}

// function to kill the given thread
uint32_t	__KLIB__KillThread(uint64_t TID, uint64_t message)
{
	// first check if the thread is in the same process
	// disable interrupts
	__asm__ __volatile__("":::"memory");
	__asm__ __volatile__("cli");
	__asm__ __volatile__("":::"memory");

	// get the current TID
	uint64_t current_TID = GetCurrentTID();

	// check if the PID matches
	// mask the bottom byte
	uint64_t test_TID = TID & 0xffffffffffffff00;
	current_TID = current_TID & 0xffffffffffffff00;

	uint32_t to_return = KILL_THREAD_NOT_IN_PROC;

	if(test_TID == current_TID)
	{
		to_return = KillThread(TID, message);
	}

	// reenable interrupts
	__asm__ __volatile__("":::"memory");
	__asm__ __volatile__("sti");
	__asm__ __volatile__("":::"memory");

	// finished, return
	return to_return;
}

// function to spawn a new system process
uint64_t	__KLIB__SpawnSystemProcess(uint64_t(*start_address)(void), void *stack_ptr, uint64_t param1, uint64_t param2, char *image_name, uint32_t image_length, char *description, uint32_t description_length)
{
	// disable interrupts
	__asm__ __volatile__("":::"memory");
	__asm__ __volatile__("cli");
	__asm__ __volatile__("":::"memory");

	uint64_t to_return = CreateSystemProc(start_address, stack_ptr, param1, param2, image_name, image_length, description, description_length);

	// reenable interrupts
	__asm__ __volatile__("":::"memory");
	__asm__ __volatile__("sti");
	__asm__ __volatile__("":::"memory");

	// finished
	return to_return;
}

// function to kill the calling process
void 		__KLIB__KillThisProcess(uint64_t exit_value)
{
	KillThisProcess(exit_value);
	return;
}















